iT邦幫忙

2023 iThome 鐵人賽

DAY 8
0

昨日介紹了利用JVM反編譯來看程式執行邏輯,Java會從編譯後的ByteCode內部指令,作為實際進行邏輯操作,今天來看執行時如何讀取使用到的類別(Class)

例外錯誤 ClassNotFoundException

首先建立 Day8.java檔案執行主要main方法

// Day8.java
package app;

class Day8{
    public static void main(String[] args){
        System.out.println("I'm Day8 Content");
    }
}

打開終端機輸入指令java Day8.java

成功執行並打印內容,去掉副檔名.java 執行指令 java Day8,會拋出錯誤訊息 ClassNotFoundException,這是因為Java執行 Class名稱非Java檔案時,會從特定路徑尋找編譯後的ByteCode,預設是環境變數設定的CLASSPATH變數,當在路徑下找不到可以執行的檔案,就會拋出ClassNotFoundException錯誤

指定編譯後的ByteCode存放位置

用法很單純,在編譯時添加 -d 指定存放類別路徑的資料夾

從終端機輸入指令 javac -d target Day8.java,可以發現自動產生target資料夾,並依據 package產生了存放ByteCode的目錄,產生後的檔案位置為target/app/Day8.class,接著使用 -cp選項預設運行根目錄target,執行Java編譯後的ByteCode

執行右方指令 java -cp target app.Day8

成功打印文字「I'm Day8 Content」,從執行流程可以推論出,在Class最上方撰寫的 pakcage xxx,是用來定義存放ByteCode的存放位置,也決定完整的類別名稱,所以匯入其他類別的寫法會是 aaa.bbb.Other,實際上就是在Class Path(cp)往下尋找 aaa/bbb/Other.class檔案

處理不同層級資料夾

現在來試著建立一個utility模組,並提供給app模組使用,在專案根目錄建立utility資料夾,接著建立Tool.java,並將package設為 utility,完成後內容如下

package utility;

public class Tool {
    private String path = "My Path in utility";

    public void printPath() {
        System.out.println(path);
    }
}

並將Day8.java內的 main方法改為建立Tool實例,並呼叫printPath方法,在重新編譯 Day8.java

執行指令 javac -d target Day8.java

import utility.Tool;
public class Day8 {
    public static void main(String[] args) {
        Tool toolClass = new Tool();
        toolClass.printPath();
    }
}

可以發現 target目錄下出現的utility資料夾內,裡面包含了 Tool Class產生的ByteCode,接著執行指令運行 Day8的main方法,在CMD輸入指令 java -cp target app.Day8,成功打印文字 My Path in utility

最後來個總結,Java在編譯時可以配合Java檔案內的Package定義,決定ByteCode實際存放的位置,無論是運行或是編譯Java程式都必須指定初始的Class Path,否則運行時會出現ClassNotFoundException例外錯誤


上一篇
第七日 從ByteCode看型別轉換
下一篇
第九日 簡介物件導向三大特性
系列文
掌握Java神器,駕馭SpringBoot猛獸30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言